﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Manager;
using SdmxMl.Structure;
using SdmxMl.Common;
using SdmxMl.Multiplexor;

using Telerik.WinControls;
using Telerik.WinControls.UI;
using Telerik.WinControls.UI.Docking;
using Telerik.WinControls.UI.Export;

namespace SdmxDiff
{
    public partial class DlgDiff : Telerik.WinControls.UI.RadForm
    {
        private CodeListType cltOld;
        private CodeListType cltNew;
        private string dummy;
        public DlgDiff()
        {
            InitializeComponent();
            radButtonExcel.Enabled = false;

            webBrowser1.DocumentText = string.Empty;
            lastDiffLangSelected = string.Empty;
            radButtonToggle.ButtonElement.ToolTipText = "Toggle Old and New references";

            //If item selected in tree is conceptscheme, concept or code or codelist, prepare urn
            if (ReferenceManager.TreeSdmx != null && ReferenceManager.TreeSdmx.SelectedNode != null)
            {
                Artefact a = ReferenceManager.TreeSdmx.SelectedNode.Tag is Artefact ?
                    ReferenceManager.TreeSdmx.SelectedNode.Tag as Artefact :
                    SdmxMl.Helper.TreeHelper.GetParentArtefact(ReferenceManager.TreeSdmx.SelectedNode);

                if (a != null && a is CodeListType)
                    textBoxRefNew.Text = UrnManager.FullIdToUrn(SdmxArtefactType.CodeLists, a.FullIdent);
            }
        }

        #region ToolTip needed Event

        private void gridView_ToolTipTextNeeded(object sender, Telerik.WinControls.ToolTipTextNeededEventArgs e)
        {
            GridDataCellElement dataCell = sender as GridDataCellElement;

            if (dataCell != null)
            {
                TextPart textPart = new TextPart(dataCell);
                SizeF size = textPart.Measure(new SizeF(float.PositiveInfinity, float.PositiveInfinity));
                SizeF sizeInCell = textPart.Measure(new SizeF(dataCell.ColumnInfo.Width, float.PositiveInfinity));

                string toolTipText = null;

                float cellWidth = dataCell.ColumnInfo.Width - dataCell.BorderWidth * 2;
                float cellHeight = dataCell.Size.Height - dataCell.BorderWidth * 2;

                if (size.Width > cellWidth || cellHeight < sizeInCell.Height)
                {
                    toolTipText = dataCell.Text;
                }

                e.ToolTipText = toolTipText;
            }
        }
        #endregion


        private UrnParser ParseRef(string refText, string target)
        {
            ArtefactRefTyped art = UrnManager.UrnToArtefactRefTyped(refText);
            if (art == null)
                throw new ApplicationException("Invalid reference in " + target);
            UrnParser p = new UrnParser(refText);
            if (p.IsSupported == false)
                throw new ApplicationException("Unsupported reference in " + target);

            return p;
        }

        private void radButtonDiff_Click(object sender, EventArgs e)
        {
            try
            {
                using (new SdmxMl.Helper.CWaitCursor())
                {
                    // Check filled
                    UrnParser pOld = ParseRef(textBoxRefOld.Text, "Old");
                    UrnParser pNew = ParseRef(textBoxRefNew.Text, "New");

                    // Check  same type
                    if (pOld.ArType != pNew.ArType)
                        throw new ApplicationException("Artefact references must be of same type");


                    // Check supported
                    if (pOld.ArType != SdmxArtefactType.CodeLists)
                        throw new ApplicationException("Sorry. Type " + pOld.ArType.ToString() + " is not yet supported");

                    // Load codelists
                    SmManager sm = ReferenceManager.GetSmContainerImage();
                    cltOld = sm.GetArtefact(SdmxArtefactType.CodeLists, pOld.TypedReference, true) as CodeListType;
                    cltNew = sm.GetArtefact(SdmxArtefactType.CodeLists, pNew.TypedReference, true) as CodeListType;


                    // make diff
                    ReportDiff report = new ReportDiff();
                    CodelistDiff clDiff = new CodelistDiff(report, cltOld, cltNew);
                    clDiff.Diff();

                    // Apply result
                    radGridView.ReadOnly = true;
                    using (radGridView.DeferRefresh())
                    {
                        radGridView.DataSource = report.ReportTable;
                        radGridView.Columns[ReportDiff.ArtefactTypeCol].Width = 90;
                        radGridView.Columns[ReportDiff.FullIdCol].Width = 150;
                        radGridView.Columns[ReportDiff.ItemCol].Width = 80;
                        radGridView.Columns[ReportDiff.SubjectCol].Width = 90;
                        radGridView.Columns[ReportDiff.CommentCol].Width = 200;
                        radGridView.Columns[ReportDiff.NewTextCol].Width = 100;
                        radGridView.Columns[ReportDiff.OldTextCol].Width = 100;


                    }
                    radGridView.MasterTemplate.EnableGrouping = false;
                    radButtonExcel.Enabled = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured during Grid phases. Reason: " + ex.Message,
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void radGridView_CellDoubleClick(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
        {
            GridDataCellElement dataCell = sender as GridDataCellElement;
            if (dataCell != null)
            {
                if (radGridView.CurrentRow != null)
                {
                    if (radGridView.CurrentRow.Cells[ReportDiff.ItemCol].Value.ToString().StartsWith("Code "))
                    {
                        string[] arr = radGridView.CurrentRow.Cells[ReportDiff.ItemCol].Value.ToString().Split(' ');
                        CodeType ct = new CodeType();
                        ct.Id = arr[1];

                        // Navigate to old ?
                        if (radGridView.CurrentRow.Cells[ReportDiff.SubjectCol].Value.ToString() == "Removed")
                            NavigateTodetail(UrnManager.FullIdToUrn(cltOld.ArType, cltOld.FullIdent, ct, null));
                        else
                            // Navigate to new
                            NavigateTodetail(UrnManager.FullIdToUrn(cltNew.ArType, cltNew.FullIdent, ct, null));
                    }
                    else if (radGridView.CurrentRow.Cells[ReportDiff.ItemCol].Value.ToString() == "Artefact")
                    {
                        NavigateTodetail(UrnManager.FullIdToUrn(cltNew.ArType, cltNew.FullIdent, null, null));
                    }


                }
            }
        }

        private void NavigateTodetail(string urn)
        {
            try
            {
                if (ReferenceManager.TreeMgr.PanelDetail != null)
                {
                    ReferenceManager.TreeMgr.PanelDetail.TabControlDetail.SelectedIndex = 0;
                    ReferenceManager.TreeMgr.PanelDetail.UpdateNodeTag(ReferenceManager.TreeSdmx.SelectedNode);
                    ReferenceManager.TreeMgr.PanelDetail.BindFromNode(null);
                    ReferenceManager.TreeSdmx.SelectedNode = null;
                }

                // If already in memory, navigate otherwhile get from registry
                UrnParser p = new UrnParser(urn);
                if (p.IsSupported)
                {
                    // If already in memory, navigate otherwhile get from regidtry
                    if (NavigationManager.LocatenavigateProject(p.ArType, p.FullIdent, p) == null)
                        NavigationManager.NavigateWithRegistry(p.ArType, p.FullIdent, true, p);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private MultiLang oldText;
        private MultiLang newText;
        private string lastDiffLangSelected;
        private void radGridView_CellClick(object sender, GridViewCellEventArgs e)
        {
            GridDataCellElement dataCell = sender as GridDataCellElement;
            if (dataCell != null)
            {
                if (radGridView.CurrentRow != null)
                {
                    DataRowView drv = radGridView.CurrentRow.DataBoundItem as DataRowView;
                    if (drv != null)
                    {
                        DataRow row = drv.Row;
                        if (row[ReportDiff.NewTextCol] is MultiLang)
                        {
                            oldText = row[ReportDiff.OldTextCol] as MultiLang;
                            newText = row[ReportDiff.NewTextCol] as MultiLang;
                            // Fetch list of lang to consider
                            string comment =  row[ReportDiff.CommentCol].ToString();
                            int index = comment.IndexOf(ReportDiff.TextDiffersMark);
                            if (index >= 0)
                            {
                                int start = index + ReportDiff.TextDiffersMark.Length; 
                                int index2 = comment.Substring(start).IndexOf(')');
                                string part = comment.Substring(start, index2);
                                List<string> langList = new List<string>(part.Split(ReportDiff.LangSpearator));
                                UpdateTextDiff(langList);
                            }
                        }
                        else
                        {
                            oldText =  newText = null;
                            UpdateTextDiff(null);
                        }
                    }
                }
            }

        }

        private void UpdateTextDiff(List<string> langList)
        {
            comboBoxLang.Items.Clear();
            webBrowser1.DocumentText = string.Empty;
            int selIndex = 0;
            if (langList != null)
            {
                foreach (string lg in langList)
                {
                    comboBoxLang.Items.Add(lg.Trim());
                    if (lg == lastDiffLangSelected)
                        selIndex = comboBoxLang.Items.Count - 1;
                }
                comboBoxLang.SelectedIndex = selIndex;
            }
            else
            {
                comboBoxLang_SelectedIndexChanged(comboBoxLang, EventArgs.Empty);
            }
        }

        private void comboBoxLang_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (oldText != null && newText != null)
            {
                // Compute the differences
                DiffMatchPatch.DiffMatchPatchEngine engine = new DiffMatchPatch.DiffMatchPatchEngine();
                List<DiffMatchPatch.Diff> diffs = engine.diff_main(
                    oldText.GetForLanguage(comboBoxLang.SelectedItem.ToString(), string.Empty), 
                    newText.GetForLanguage(comboBoxLang.SelectedItem.ToString(), string.Empty));
                engine.diff_cleanupSemantic(diffs);
                webBrowser1.DocumentText = engine.diff_prettyHtml(diffs);
                lastDiffLangSelected = comboBoxLang.SelectedItem.ToString();
            }
        }

        private void radButtonRegistryVersion_Click(object sender, EventArgs e)
        {
            DlgVersions aDlg = new DlgVersions();
            aDlg.BindVersionsOf(textBoxRefNew.Text);
            if (aDlg.ShowDialog(this) == DialogResult.OK)
            {
                textBoxRefOld.Text = aDlg.SelectedVersionUrn;
            }

        }

        private void radButtonToggle_Click(object sender, EventArgs e)
        {
            string temp = textBoxRefOld.Text;
            textBoxRefOld.Text = textBoxRefNew.Text;
            textBoxRefNew.Text = temp;
        }

        #region Excel export

        /// <summary>Excel Export Event</summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void radMenuItemExportExcel_Click(object sender, EventArgs e)
        {
            RunExportToExcelML();
        }

        /// <summary> Export Grid to Excel </summary>
        private void RunExportToExcelML()
        {
            ExportToExcelML excelExporter = null;
            try
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                excelExporter = new ExportToExcelML(this.radGridView);
                excelExporter.ExcelCellFormatting += excelExporter_ExcelCellFormatting;
                excelExporter.SummariesExportOption = SummariesOption.ExportAll;
                //set export settings
                excelExporter.ExportVisualSettings = true;
                excelExporter.ExportHierarchy = true;
                excelExporter.HiddenColumnOption = HiddenOption.DoNotExport;

                this.Cursor = Cursors.WaitCursor;
                saveFileDialog.Filter = "Excel (*.xls)|*.xls";
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    excelExporter.RunExport(saveFileDialog.FileName);
                    excelExporter.ExcelCellFormatting -= excelExporter_ExcelCellFormatting;

                    DialogResult dr = RadMessageBox.Show("The data in the grid was exported successfully. Do you want to open the file?",
                        "Export to Excel", MessageBoxButtons.YesNo, RadMessageIcon.Question);
                    if (dr == DialogResult.Yes)
                    {
                        System.Diagnostics.Process.Start(saveFileDialog.FileName);
                    }
                }
            }
            catch (Exception ex)
            {
                RadMessageBox.Show(this, ex.Message, "I/O Error", MessageBoxButtons.OK, RadMessageIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;

            }
        }

        /// <summary>
        /// Catch event to translate multilang object cell to current language string for excel cell
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        void excelExporter_ExcelCellFormatting(object sender, Telerik.WinControls.UI.Export.ExcelML.ExcelCellFormattingEventArgs e)
        {
            if (e.GridRowIndex >= 0 && (e.GridCellInfo.ColumnInfo.Name == ReportDiff.NewTextCol || e.GridCellInfo.ColumnInfo.Name == ReportDiff.OldTextCol))
            {
                e.ExcelCellElement.Data.DataType = Telerik.WinControls.UI.Export.ExcelML.DataType.String;
                MultiLang ml = e.GridCellInfo.Value as MultiLang;
                if (ml != null)
                    e.ExcelCellElement.Data.DataItem = ml.ToString();
            }
        }


        #endregion


    }
}
